import time
import math
import random
import json

import numpy as np

from application.config import DB
from application.http.models import CodeModel
from sanren.utils import Helper
from sanren.utils.utils import Utils
from sanren.extensions import MyLogger


# 订单生码 job
class OrderGenerationJob:
    """生码类型 对应说明

        0 流水号
        1 随机数字
        2 大写字母
        3 小写字母
        4 大小写字母
        5 大写字母数字
        6 小写字母数字
    """
    # 日志记录器
    log = None

    # 全局订单信息
    obj_order = None

    # 企业信息
    obj_company = None

    # 码 model
    model_code = None

    # 已经生码量
    code_total = 0

    # init 实例化
    def __init__(self, params, log=None):
        if log is None:
            self.log = MyLogger('order.gen.job')
        else:
            self.log = log

        self.params = params
        # 码库 model
        self.model_code = CodeModel.get_code_model(params['company_code'])

    # 打印 log
    def info(self, msg):
        self.log.logger.info(msg)

    # run
    def run(self):
        start_time = time.time()

        # 生码
        self.obj_order = CodeModel.Order.where('batch_sn', self.params['batch_sn']).first()
        if self.obj_order is None:
            self.info('Generation Code: 找不到此生码单')
            return 700404

        # 生码单状态
        if self.obj_order.status not in (0, 1, 3, 4):
            self.info('Generation Code: 已经成功或取消的生码单不能再进行生码操作')
            return 700403

        # 套标
        # 标准码
        if self.obj_order.counts == self.obj_order.queue_finish_counts:
            self.info('Generation Code: 已经成功生码, 不需要再进行生码操作')
            return 700200

        DB.begin_transaction('postgres')
        # 开始生码
        try:
            # 生码
            self.info('==========================生码信息开始========================')
            self.info(f'Generation Code: 正式开始生码,batch_sn: {self.obj_order.batch_sn}, order_sn: {self.obj_order.order_sn}')
            # 码表
            self.obj_company = self.obj_order.brand

            # 已经生码量已生码量 默认+1
            self.code_total = self.model_code.count('id as total').first().total
            self.code_total = int(self.code_total) + 1 if self.code_total is not None else 1

            # 根据订单生对应码
            # type 1 套标 2 标准码
            if self.obj_order.type == 1:
                # 套码
                codes = self.group_code()
            elif self.obj_order.type == 2:
                # 标准码
                codes = self.standard_code(counts=self.params['counts'])
            else:
                self.info('==========================不支持的生码类型========================')

            # 写入数据 查看前5条
            self.info('==========================开始写数据库========================')

            # 多少份拆一组
            # limit_num = 100000
            # if len(codes) > limit_num:
            #     # 共有多少份
            #     item_id_list = [codes[i: i + limit_num] for i in range(0, len(codes), limit_num)]
            #     for i in range(len(item_id_list)):
            #         self.model_code.bulk_create(item_id_list[i])
            #         self.info('分条写数据库, 当前第: ', i)
            # else:
            #     self.model_code.bulk_create(codes)
            limit_num = 100000
            if len(codes) > limit_num:
                for_num = math.ceil(len(codes) / limit_num)
                for i in range(for_num):
                    self.model_code.bulk_create(codes[i * limit_num: (i + 1) * limit_num])
                    self.info('分条写数据库, 当前第: ', i)
            else:
                self.model_code.bulk_create(codes)

            # 更新生码状态 2 完成 done
            # obj_order.status = 2
            if self.obj_order.small_status and self.obj_order.small_type == 1:
                # 更新商户配置状态
                setting = CodeModel.Setting.get_cratch_obj(code=self.obj_order.company_code)
                setting_val = json.loads(setting.value)

                len_key = f'length_{self.obj_order.small_length}'
                if setting_val[len_key] == 0:
                    setting_val[len_key] = int(self.params['counts'])
                else:
                    setting_val[len_key] = int(setting_val[len_key]) + int(self.params['counts'])
                setting.value = json.dumps(setting_val)

            # 更新队列状态
            self.obj_order.queue_status = 1
            if self.obj_order.queue_finish_counts is None or self.obj_order.queue_finish_counts == '':
                self.obj_order.queue_finish_counts = int(self.params['counts'])
            else:
                self.obj_order.queue_finish_counts = int(self.obj_order.queue_finish_counts) + int(self.params['counts'])
            self.obj_order.queue_finish_status = int(self.obj_order.queue_finish_counts / int(self.obj_order.counts) * 100)

            # 只生一次的码
            if self.obj_order.queue_finish_status == 100 and self.obj_order.queue_finish_counts == self.obj_order.counts:
                # 生码状态为2 完成
                self.obj_order.status = 2
                # 生码队列状态为2 完成
                self.obj_order.queue_status = 2
                self.obj_order.queue_error_reason = None

            self.obj_order.save()

            DB.commit('postgres')
            self.info('==========================写数据库成功========================')

            # raise Exception('测试出错') # 测试事务
        except Exception as e:
            # 异常
            DB.rollback('postgres')
            self.info('==========================出错啦========================')
            self.info(repr(e))

            # 更新生码状态 为 3 取消 4 错误
            self.obj_order.status = 4
            self.obj_order.error_reason = '写入数据库失败'
            self.obj_order.queue_status = 4
            self.obj_order.queue_error_reason = str(e)
            self.obj_order.save()

        process_time = time.time() - start_time
        self.info(f'共用时: {process_time}')
        self.info('==========================生码信息结束========================')

    # 生码总控制
    def create_code(self, id):
        start_time = time.time()

        self.info('==========================生码信息获取========================')
        # 订单信息
        self.obj_order = CodeModel.Order.find(id)
        if self.obj_order is None:
            self.info('生码单不存在!')
            return

        # 获取商户信息
        self.obj_company = self.obj_order.company
        if self.obj_company is None:
            self.info('商户不存在!')
            return

        # 获取商户码表
        self.model_code = CodeModel.get_code_model(prefix=self.obj_company.code)
        if self.model_code is None:
            self.info('码表不存在!')
            return

        # 开始生码
        self.info('==========================开始生码========================')
        # 状态为 1 开始中才进行生码操作
        if self.obj_order.status not in [0, 1, 3, 4]:
            self.info('重复生码请求!')
            return

        DB.begin_transaction('postgres')
        # 开始生码
        try:
            # 开启事务
            if self.obj_order.type == 1:
                # 前关联 套码
                codes = self.group_code()
            else:
                # 前关联 标准码
                # 码类型 0 流水号 1 随机数字 2 大写字母 3 小写字母 4 大小写字母 5 大写字母数字 6 小写字母数字
                codes = self.standard_code()

            # 写入数据 查看前5条
            self.info('============开始写数据库:', codes[0])
            limit_num = 100000
            if len(codes) > limit_num:
                for_num = math.ceil(len(codes) / limit_num)
                for i in range(for_num):
                    self.model_code.bulk_create(codes[i * limit_num: (i + 1) * limit_num])
                    self.info('分条写数据库, 当前第: ', i)
            else:
                self.model_code.bulk_create(codes)
            self.info('写数据库成功')

            # 提交保存
            DB.commit('postgres')
        except Exception as e:
            # 异常
            DB.rollback('postgres')

            # 更新生码状态 4 执行失败
            self.obj_order.status = 4
            self.obj_order.error_reason = str(e)
            self.obj_order.save()

            self.info('==========================出错啦.....')
            raise Exception

        else:
            # 如果没有异常发生
            # 更新生码状态 2 完成 done
            self.obj_order.status = 2
            self.obj_order.error_reason = None
            self.obj_order.save()

        self.info('==========================生码信息结束========================')

        process_time = time.time() - start_time
        self.info(f'共用时: {process_time}')

    # 生码 标准码
    def standard_code(self, counts=1):
        # 生成码量 指定量
        length_data = int(counts)

        # 判断 流水号 大标 中标 小标、 防伪码 、 验证码
        # 流水号
        if self.obj_order.serial_status:
            self.info(f'开始生成流水号，码量为{length_data}')
            serial_code = self.create_serial_code(counts=int(length_data))
            self.info(f'已生成 serial_code len: {len(serial_code)}')

            # 计算 小标流水区间
            if self.obj_order.serial_type == 0:
                new_serial_codes = serial_code.copy()
                new_serial_codes = sorted(new_serial_codes)
                if self.obj_order.serial_serial_start is None or self.obj_order.serial_serial_start == '':
                    self.obj_order.serial_serial_start = new_serial_codes[0]
                self.obj_order.serial_serial_end = new_serial_codes[-1]
                self.info(f'min  {self.obj_order.serial_serial_start} max {self.obj_order.serial_serial_end}')

        # 大标
        if self.obj_order.big_status:
            self.info(f'开始生成大标，码量为{length_data}')
            big_code = self.create_big_code(counts=length_data)
            self.info(f'已生成 big_code len:{len(big_code)}')

            # 计算 大标流水区间
            if self.obj_order.big_type == 0:
                new_big_codes = big_code.copy()
                new_big_codes = sorted(new_big_codes)
                if self.obj_order.big_serial_start is None or self.obj_order.big_serial_start == '':
                    self.obj_order.big_serial_start = new_big_codes[0]
                self.obj_order.big_serial_end = new_big_codes[-1]

            # 大标验证码
            if self.obj_order.big_verify_status:
                self.info(f'开始生成大标验证码，码量为{length_data}')
                big_verify_code = self.create_big_verify_code(counts=length_data)
                self.info(f'已生成 big_verify_code len: {len(big_verify_code)}')

        # 中标
        if self.obj_order.middle_status:
            self.info(f'开始生成中标，码量为{length_data}')
            middle_code = self.create_middle_code(counts=length_data)
            self.info(f'已生成 middle_code len: {len(middle_code)}')

            # 计算 中标流水区间
            if self.obj_order.middle_type == 0:
                new_middle_codes = middle_code.copy()
                new_middle_codes = sorted(new_middle_codes)
                if self.obj_order.middle_serial_start is None or self.obj_order.middle_serial_start == '':
                    self.obj_order.middle_serial_start = new_middle_codes[0]
                self.obj_order.middle_serial_end = new_middle_codes[-1]

            # 中标验证码
            if self.obj_order.middle_verify_status:
                self.info(f'开始生成中标验证码，码量为{length_data}')
                middle_verify_code = self.create_middle_verify_code(counts=length_data)
                self.info(f'已生成 middle_verify_code len: {len(middle_verify_code)}')

        # 小码
        if self.obj_order.small_status:
            self.info(f'开始生成小码，码量为{length_data}')
            small_code = self.create_small_code(counts=length_data)
            self.info(f'已生成 small_code len: {len(small_code)}')

            # 计算 小标流水区间
            if self.obj_order.small_type == 0:
                new_small_codes = small_code.copy()
                new_small_codes = sorted(new_small_codes)
                if self.obj_order.small_serial_start is None or self.obj_order.small_serial_start == '':
                    self.obj_order.small_serial_start = new_small_codes[0]
                self.obj_order.small_serial_end = new_small_codes[-1]

        # 防伪码
        if self.obj_order.security_status:
            self.info(f'开始生成防伪码，码量为{length_data}')
            security_code = self.create_security_code(counts=length_data)
            self.info(f'已生成 security_code len: {len(security_code)}')

        # 验证码
        if self.obj_order.verify_status:
            self.info(f'开始生成验证码，码量为{length_data}')
            verify_code = self.create_verify_code(counts=length_data)
            self.info(f'已生成 verify_code len: {len(verify_code)}')

        # 预写入数据库
        codes = list()
        for n in range(length_data):
            item = dict()
            item['batch_sn'] = self.obj_order.batch_sn
            item['batch_num'] = self.obj_order.batch_num
            # 查询方式
            item['query_type'] = self.obj_order.query_type
            # 默认码为启用状态
            item['status'] = 0
            # 大标
            if self.obj_order.big_status:
                item['big_code'] = str(big_code[n])
                # 大标验证码
                if self.obj_order.big_verify_status:
                    item['big_verify_code'] = str(big_verify_code[n])
            # 中标
            if self.obj_order.middle_status:
                item['middle_code'] = str(middle_code[n])
                # 中标验证码
                if self.obj_order.middle_verify_status:
                    item['middle_verify_code'] = str(middle_verify_code[n])
            # 流水号
            if self.obj_order.serial_status:
                item['serial_code'] = serial_code[n]
            # 小标 刮刮码
            if self.obj_order.small_status:
                item['small_code'] = str(small_code[n])
            # 防伪码
            if self.obj_order.security_status:
                item['security_code'] = str(security_code[n])
            # 验证码
            if self.obj_order.verify_status:
                item['verify_code'] = str(verify_code[n])
            codes.append(item)

        return codes

    # 生码 套标
    def group_code(self):
        # 判断 self.obj_order 三个参数 小码、 防伪码 、 验证码
        # 计算大 中 小标量
        # 1000 * 1 = 1000 大标
        big_counts = int(self.obj_order.counts)
        # 1000 * 5 = 5000 中标
        middle_counts = int(self.obj_order.counts * self.obj_order.middle_counts)
        # 1000 * 10 = 10000 小标
        small_counts = int(self.obj_order.counts * self.obj_order.small_counts)
        if middle_counts and self.obj_order.small_status:
            small_counts = int(self.obj_order.counts * self.obj_order.middle_counts * self.obj_order.small_counts)
        else:
            small_counts = int(self.obj_order.counts * self.obj_order.small_counts)
        print(f'套码生码:  big_counts:{big_counts}, middle_counts: {middle_counts}, small_counts: {small_counts}')

        # 生码规则配置:
        # code_type 1 全数字 2 全字母 3 数字字母
        # type 1 数字码随机数字  2 数字码顺序流水号 3 乱码
        # 大码
        if self.obj_order.big_status:
            print(f'开始生成大标码，码量为{big_counts}')
            big_code = self.create_big_code(counts=big_counts)
            print(f'已生成 big_code len: {len(big_code)}')

            if self.obj_order.big_type == 0:
                # 计算 小标流水区间
                new_big_codes = big_code.copy()
                new_big_codes = sorted(new_big_codes)
                self.obj_order.big_serial_start = new_big_codes[0]
                self.obj_order.big_serial_end = new_big_codes[-1]

            # # 大标验证码
            # if self.obj_order.big_verify_status:
            #     print(f'开始生成大标验证码，码量为{big_counts}')
            #     big_verify_code = self.create_big_verify_code(counts=big_counts)
            #     print(f'已生成 big_verify_code len: {len(big_verify_code)}')

        # 中码
        if self.obj_order.middle_status:
            print(f'开始生成中标码，码量为{middle_counts}')
            middle_code = self.create_middle_code(counts=middle_counts)
            print(f'已生成 middle_code len: {len(middle_code)}')

            if self.obj_order.middle_type == 0:
                # 计算 小标流水区间
                new_middle_codes = middle_code.copy()
                new_middle_codes = sorted(new_middle_codes)
                self.obj_order.middle_serial_start = new_middle_codes[0]
                self.obj_order.middle_serial_end = new_middle_codes[-1]

            # # 中标验证码
            # if self.obj_order.middle_verify_status:
            #     print(f'开始生成中标验证码，码量为{middle_counts}')
            #     middle_verify_code = self.create_middle_verify_code(counts=middle_counts)
            #     print(f'已生成 middle_verify_code len: {len(middle_verify_code)}')

        # 小码
        if self.obj_order.small_status:
            print(f'开始生成小码，码量为{small_counts}')
            small_code = self.create_small_code(counts=small_counts)
            print(f'已生成 small_code len: {len(small_code)}')

            if self.obj_order.small_type == 0:
                # 计算 小标流水区间
                new_small_codes = small_code.copy()
                new_small_codes = sorted(new_small_codes)
                self.obj_order.small_serial_start = new_small_codes[0]
                self.obj_order.small_serial_end = new_small_codes[-1]

        # 防伪码
        if self.obj_order.security_status:
            print(f'开始生成防伪码，码量为{small_counts}')
            security_code = self.create_security_code(counts=small_counts)
            print(f'已生成 security_code len: {len(security_code)}')

        # 验证码
        if self.obj_order.verify_status:
            print(f'开始生成验证码，码量为{small_counts}')
            verify_code = self.create_verify_code(counts=small_counts)
            print(f'已生成 verify_code len: {len(verify_code)}')

        # 合成需要的数据，并写入数据库
        # 需要合并的数据有那些
        codes = list()
        # 最大 count
        max_counts = max(big_counts, middle_counts, small_counts)
        # # 套标标识
        # tmp_big_verify_code = None
        # tmp_middle_verify_code = None
        for n in range(max_counts):
            item = dict()
            item['batch_sn'] = self.obj_order.batch_sn
            item['batch_num'] = self.obj_order.batch_num
            # 查询方式
            item['query_type'] = self.obj_order.query_type
            # 默认码为未启用状态
            item['status'] = 0
            # 大标
            if self.obj_order.big_status:
                if self.obj_order.middle_status and n % (self.obj_order.middle_counts * self.obj_order.small_counts) == 0:
                    tmp_big_code = big_code.pop(0)
                    # if self.obj_order.big_verify_status:
                    #     tmp_big_verify_code = big_verify_code.pop(0)
                elif not self.obj_order.middle_status and self.obj_order.small_status and n % self.obj_order.small_counts == 0:
                    tmp_big_code = big_code.pop(0)
                    # if self.obj_order.big_verify_status:
                    #     tmp_big_verify_code = big_verify_code.pop(0)
                elif not self.obj_order.small_status:
                    tmp_big_code = big_code.pop(0)
                    # if self.obj_order.big_verify_status:
                    #     tmp_big_verify_code = big_verify_code.pop(0)

                item['big_code'] = tmp_big_code
                # if tmp_big_verify_code is not None:
                #     item['big_verify_code'] = str(tmp_big_verify_code)

            # 中标
            if self.obj_order.middle_status:
                if self.obj_order.small_status and n % self.obj_order.small_counts == 0:
                    tmp_middle_code = middle_code.pop(0)
                    # if self.obj_order.middle_verify_status:
                    #     tmp_middle_verify_code = middle_verify_code.pop(0)
                elif not self.obj_order.small_status:
                    tmp_middle_code = middle_code.pop(0)
                    # if self.obj_order.middle_verify_status:
                    #     tmp_middle_verify_code = middle_verify_code.pop(0)

                item['middle_code'] = tmp_middle_code
                # if tmp_middle_verify_code is not None:
                #     item['middle_verify_code'] = str(tmp_middle_verify_code)

            if self.obj_order.small_status:
                item['small_code'] = small_code[n]
            if self.obj_order.security_status:
                item['security_code'] = security_code[n]
            if self.obj_order.verify_status:
                item['verify_code'] = str(verify_code[n])

            codes.append(item)

        return codes

    # 创建 大标
    def create_big_code(self, counts=1):
        # 码类型
        code_type_field = 'big_code'
        # 加密盐
        salt = 'big' + str(self.obj_order.company_code)

        # 已生码量 默认+1
        code_total = self.model_code.count('id as total').first().total
        code_total += 1

        # 生码 0 流水号 1 随机数字 2 大写字母 3 小写字母 4 大小写字母 5 大写字母数字 6 小写字母数字
        code_type = int(self.obj_order.big_type)
        if code_type == 0:
            # 0 流水号
            # 获取中码最大值 并加上当前 len(codes)
            last_serial_max = CodeModel.Order.max(
                'small_serial_end as max'
            ).where(
                'company_code', self.obj_order.company_code
            ).where('big_status', True).where('big_type', 0).first().max

            # 格式化
            max_serial = 0
            if last_serial_max:
                max_serial = int(last_serial_max)

            if int(self.obj_order.big_diy_status) == 1:
                big_diy_value = int(self.obj_order.big_diy_value)
                # 自定义 流水号
                number = max_serial + 1 if max_serial and max_serial >= big_diy_value else big_diy_value
            else:
                # 默认 流水号
                number = max_serial + 1 if max_serial else 1
            code_item = [Utils.create_serial_number(number=number + num, length=self.obj_order.big_length) for num in range(counts)]
        elif code_type == 1:
            # 随机数字
            code_item = self.create_number(code_length=self.obj_order.big_length, type=code_type_field, size=counts)
        elif code_type in [2, 3, 4, 5, 6]:
            code_item = [Utils.create_random_hash_str(number=code_total + num, length=self.obj_order.big_length, salt=salt, type=code_type) for num in range(counts)]

        return code_item

    # 创建 中标
    def create_middle_code(self, counts=1):
        # 码类型
        code_type_field = 'middle_code'
        # 加密盐
        salt = 'middle' + str(self.obj_order.company_code)

        # 已生码量 默认+1
        code_total = self.model_code.count('id as total').first().total
        code_total += 1

        # 生码 0 流水号 1 随机数字 2 大写字母 3 小写字母 4 大小写字母 5 大写字母数字 6 小写字母数字
        code_type = int(self.obj_order.middle_type)
        if code_type == 0:
            # 获取中码最大值 并加上当前 len(codes)
            last_serial_max = CodeModel.Order.max(
                'middle_serial_end as max'
            ).where(
                'company_code', self.obj_order.company_code
            ).where('middle_status', True).where('middle_type', 0).first().max
            # 格式化
            max_serial = 0
            if last_serial_max:
                max_serial = int(last_serial_max)

            if int(self.obj_order.middle_diy_status) == 1:
                middle_diy_value = int(self.obj_order.middle_diy_value)
                # 自定义 流水号
                number = max_serial + 1 if max_serial and max_serial >= middle_diy_value else middle_diy_value
            else:
                # 默认 流水号
                number = max_serial + 1 if max_serial else 1
            code_item = [Utils.create_serial_number(number=number + num, length=self.obj_order.middle_length) for num in range(counts)]
        elif code_type == 1:
            code_item = self.create_number(code_length=self.obj_order.middle_length, type=code_type_field, size=counts)
        elif code_type in [2, 3, 4, 5, 6]:
            code_item = [Utils.create_random_hash_str(number=code_total + num, length=self.obj_order.middle_length, salt=salt, type=code_type) for num in range(counts)]

        return code_item

    # 创建 小标 刮刮码
    def create_small_code(self, counts=1):
        # 0 流水号 1 随机数字 2 大写字母 3 小写字母 4 大小写字母 5 大写字母数字 6 小写字母数字
        code_type = int(self.obj_order.small_type)
        if code_type == 0:  # 流水号
            # 获取中码最大值 并加上当前 len(codes)
            last_serial_max = CodeModel.Order.max(
                'small_serial_end as max'
            ).where(
                'company_code', self.obj_order.company_code
            ).where('small_status', True).where('small_type', 0).first().max
            # 格式化
            max_serial = 0
            if last_serial_max:
                max_serial = int(last_serial_max)

            if int(self.obj_order.serial_diy_status) == 1:
                small_diy_value = int(self.obj_order.small_diy_value)
                # 自定义 流水号
                number = max_serial + 1 if max_serial and max_serial >= small_diy_value else small_diy_value
            else:
                # 默认 流水号
                number = max_serial + 1 if max_serial else 1
            return [Utils.create_serial_number(number=number + num, length=self.obj_order.small_length) for num in range(counts)]
        elif code_type == 1:  # 随机数字
            # 码类型
            code_type_field = 'small_code'

            return self.create_number(code_length=self.obj_order.small_length, type=code_type_field, size=counts)
        elif code_type in [2, 3, 4, 5, 6]:
            # 加密盐
            salt = 'small' + str(self.obj_order.company_code)

            if (self.obj_order.small_prefix is not None and self.obj_order.small_prefix != '' and len(self.obj_order.small_prefix) > 0) or (self.obj_order.small_suffix is not None and self.obj_order.small_suffix != '' and len(self.obj_order.small_suffix) > 0):
                return [self.obj_order.small_prefix + Utils.create_random_hash_str(number=self.code_total + num, length=self.obj_order.small_length, salt=salt, type=code_type) + self.obj_order.small_suffix for num in range(counts)]
            else:
                return [Utils.create_random_hash_str(number=self.code_total + num, length=self.obj_order.small_length, salt=salt, type=code_type) for num in range(counts)]
        else:
            return []

    # 创建 防伪码
    def create_security_code(self, counts=1):
        # 生码 0 流水号 1 随机数字 2 大写字母 3 小写字母 4 大小写字母 5 大写字母数字 6 小写字母数字
        code_type = int(self.obj_order.security_type)
        if code_type == 1:
            # 随机数字
            # 码类型
            code_type_field = 'security_code'

            return self.create_number(code_length=self.obj_order.security_length, type=code_type_field, size=counts)
        elif code_type in [2, 3, 4, 5, 6]:
            # 加密盐
            salt = 'security' + str(self.obj_order.company_code)
            return [Utils.create_random_hash_str(number=self.code_total + num, length=self.obj_order.security_length, salt=salt, type=code_type) for num in range(counts)]
        else:
            return []

    # 创建 大标验证码
    def create_big_verify_code(self, counts=1):
        # 加密盐
        salt = 'bigverify' + str(self.obj_order.company_code)

        # 已生码量 默认+1
        code_total = self.model_code.count('id as total').first().total
        code_total += 1
        # 生码 0 流水号 1 随机数字 2 大写字母 3 小写字母 4 大小写字母 5 大写字母数字 6 小写字母数字
        code_type = int(self.obj_order.big_verify_type)
        if code_type == 0:
            # 流水号
            number = random.randint(1, 10**int(self.obj_order.big_verify_length - 1))
            code_item = [Utils.create_serial_number(number=number + num, length=self.obj_order.big_verify_length) for num in range(counts)]
        elif code_type == 1:
            # 随机数字
            np.random.seed(int(self.obj_order.batch_num))
            low = 10**(self.obj_order.big_verify_length - 1)
            high = (10**self.obj_order.big_verify_length) - 1
            np_code_item = np.random.randint(low=low, high=high, size=counts, dtype=np.uint64)
            code_item = list(np_code_item)
        elif code_type in [2, 3, 4, 5, 6]:
            code_item = [Utils.create_random_hash_str(number=code_total + num, length=self.obj_order.big_verify_length, salt=salt, type=code_type) for num in range(counts)]

        return code_item

    # 创建 中标验证码
    def create_middle_verify_code(self, counts=1):
        # 加密盐
        salt = 'middleverify' + str(self.obj_order.company_code)

        # 已生码量 默认+1
        code_total = self.model_code.count('id as total').first().total
        code_total += 1

        # 生码 0 流水号 1 随机数字 2 大写字母 3 小写字母 4 大小写字母 5 大写字母数字 6 小写字母数字
        code_type = int(self.obj_order.middle_verify_type)
        if code_type == 0:
            # 流水号
            number = random.randint(1, 10**int(self.obj_order.middle_verify_length - 1))
            code_item = [Utils.create_serial_number(number=number + num, length=self.obj_order.middle_verify_length) for num in range(counts)]
        elif code_type == 1:
            # 随机数字
            np.random.seed(int(self.obj_order.batch_num))
            low = 10**(self.obj_order.middle_verify_length - 1)
            high = (10**self.obj_order.middle_verify_length) - 1
            np_code_item = np.random.randint(low=low, high=high, size=counts, dtype=np.uint64)
            code_item = list(np_code_item)
        elif code_type in [2, 3, 4, 5, 6]:
            code_item = [Utils.create_random_hash_str(number=code_total + num, length=self.obj_order.middle_verify_length, salt=salt, type=code_type) for num in range(counts)]

        return code_item

    # 创建 验证码
    def create_verify_code(self, counts=1):
        # 生码 0 流水号 1 随机数字 2 大写字母 3 小写字母 4 大小写字母 5 大写字母数字 6 小写字母数字
        code_type = int(self.obj_order.verify_type)
        if code_type == 0:
            # 流水号
            number = random.randint(1, 10**int(self.obj_order.verify_length - 1))
            return [Utils.create_serial_number(number=number + num, length=self.obj_order.verify_length) for num in range(counts)]
        elif code_type == 1:
            # 随机数字
            np.random.seed(int(self.obj_order.batch_num))
            low = 10**(self.obj_order.verify_length - 1)
            high = (10**self.obj_order.verify_length) - 1
            np_code_item = np.random.randint(low=low, high=high, size=counts, dtype=np.uint64)
            return list(np_code_item)
        elif code_type in [2, 3, 4, 5, 6]:
            # 加密盐 批次号
            salt = 'verify' + str(self.obj_order.batch_sn)
            return [Utils.create_random_hash_str(number=num, length=self.obj_order.verify_length, salt=salt, type=code_type) for num in range(counts)]
        else:
            return []

    # 创建 流水号码
    def create_serial_code(self, counts=1):
        # 0 流水号
        last_max_serial = CodeModel.Order.max('serial_serial_end as max').where(
            'company_code', self.obj_order.company_code
        ).where('serial_type', 0)
        # 有商品信息，从头开始计算流水号
        if self.obj_order.good_code is not None and self.obj_order.good_code != '' and len(self.obj_order.good_code) > 0:
            last_max_serial = last_max_serial.where('good_code', self.obj_order.good_code)
        else:
            last_max_serial = last_max_serial.where_null('good_code')
        # 取最大流水号值
        last_max_serial = last_max_serial.first().max
        # 格式化
        max_serial = 0
        if last_max_serial:
            max_serial = int(last_max_serial)

        if self.obj_order.serial_diy_status:
            serial_diy_value = int(self.obj_order.serial_diy_value)
            # 自定义 流水号
            number = max_serial + 1 if max_serial and max_serial >= serial_diy_value else serial_diy_value
        else:
            # 默认 流水号
            number = max_serial + 1 if max_serial else 1

        # 返回流水号
        return [Helper.serial_number(number=(number + i), length=int(self.obj_order.serial_length)) for i in range(counts)]

    # 创建 随机数字码
    def create_number(self, code_length=6, type='small_code', size=1):
        # 刮刮码添加前后缀 标识
        is_small_code = False
        if type == 'small_code':
            is_small_code = True

        codes = set()
        while len(codes) < size:
            if code_length >= 20:
                code_item = Utils.create_big_random_number(length=code_length)
            else:
                code_item = Utils.create_random_int(length=code_length)
            code_item = str(code_item)

            # 判断是否存在
            if code_item in codes:
                continue

            if is_small_code:
                # 刮刮码添加前后缀
                small_code_str = ''
                if self.obj_order.small_prefix and self.obj_order.small_prefix != '':
                    small_code_str += str(self.obj_order.small_prefix)
                small_code_str += code_item
                if self.obj_order.small_suffix and self.obj_order.small_suffix != '':
                    small_code_str += str(self.obj_order.small_suffix)
                # 刮刮码拼接
                code_item = small_code_str

            # 判断是否存在
            if not self.code_exist_db(type=type, code=code_item):
                codes.add(code_item)

            # self.info(msg=f'已生成 {type} len: {len(codes)}')

        return list(codes)

    # 判断码是否存在码库
    def code_exist_db(self, type, code):
        if type == 'small_code':
            return self.model_code.where('small_code', code).exists()
        elif type == 'security_code':
            return self.model_code.where('security_code', code).exists()
        elif type == 'middle_code':
            return self.model_code.where('middle_code', code).exists()
        elif type == 'big_code':
            return self.model_code.where('big_code', code).exists()
        else:
            return True
